package com.atguigu.gulimall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.exception.NoStockException;
import com.atguigu.common.to.mq.OrderTo;
import com.atguigu.common.to.mq.StockDetailTo;
import com.atguigu.common.to.mq.StockLockedTo;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.atguigu.gulimall.ware.entity.WareOrderTaskEntity;
import com.atguigu.gulimall.ware.feign.OrderFeignService;
import com.atguigu.gulimall.ware.service.WareOrderTaskDetailService;
import com.atguigu.gulimall.ware.service.WareOrderTaskService;
import com.atguigu.gulimall.ware.vo.*;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.rabbitmq.client.Channel;
import lombok.Data;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.ware.dao.WareSkuDao;
import com.atguigu.gulimall.ware.entity.WareSkuEntity;
import com.atguigu.gulimall.ware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.NativeWebRequest;
import sun.awt.geom.AreaOp;

import javax.annotation.Resource;




@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {
	@Resource
	WareSkuDao wareSkuDao;

	@Autowired
	RabbitTemplate rabbitTemplate;

	@Autowired
	WareOrderTaskService orderTaskService;

	@Autowired
	OrderFeignService orderFeignService;

	@Autowired
	WareOrderTaskDetailService orderTaskDetailService;


	private void unLockStock(Long skuId, Long wareId, Integer skuNum, Long detailId) {
		//库存解锁
		wareSkuDao.unlockStock(skuId,wareId,skuNum);
		//更新库存工作单的状态
		WareOrderTaskDetailEntity entity = new WareOrderTaskDetailEntity();
		entity.setId(detailId);
		entity.setLockStatus(2);//更改为已解锁
		orderTaskDetailService.updateById(entity);
	}

	@Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

	@Override
	public List<SkuHasStockVo> getSkuHasStock(List<Long> skuIds) {

		List<SkuHasStockVo> collect = skuIds.stream().map(skuId -> {
			SkuHasStockVo vo = new SkuHasStockVo();

			//查询当前sku的总库存量
			Long count = baseMapper.getSkuStock(skuId);

			vo.setSkuId(skuId);
			vo.setHasStock(count == null ? false : count > 0);
			return vo;

		}).collect(Collectors.toList());
		return collect;
	}


	/**
	 *库存锁定场景
	 * 1)、下订单成功，订单过期没有支付被系统自动取消，被用户手动取消，都要解锁库存
	 *
	 * 2)、下订单成功，库存锁定成功，接下来得业务调用失败，导致订单回滚。
	 * 		之前锁定得库存就要自动解锁。
	 */
	//为某个订单锁定库存
	@Transactional
	@Override
	public Boolean orderLockStock(WareSkuLockVo vo) {

		/**
		 * 保存库存工作单的详情
		 * 追溯
		 */
		WareOrderTaskEntity taskEntity = new WareOrderTaskEntity();
		taskEntity.setOrderSn(vo.getOrderSn());
		orderTaskService.save(taskEntity);


		//1、找到下单的收货地址，找到一个就近仓库，锁定库存。
		//找到每个商品再哪个仓库都有库存
		List<OrderItemVo> locks = vo.getLocks();
		List<SkuWareHasStock> collect = locks.stream().map(item -> {
			SkuWareHasStock stock = new SkuWareHasStock();
			Long skuId = item.getSkuId();
			stock.setSkuId(skuId);
			stock.setNum(item.getCount());
			//查询这个商品在哪里有库存
			List<Long> wareIds = wareSkuDao.listWareIdHasSkuStock(skuId);
			return stock;
		}).collect(Collectors.toList());

		Boolean allLock = true;
		//锁定库存
		for (SkuWareHasStock hasStock : collect) {
			Boolean skuStocked = false;
			Long skuId = hasStock.getSkuId();
			List<Long> wareIds = hasStock.getWareId();
			if (wareIds == null || wareIds.size() == 0){
				//没有任何仓库有这个商品的库存
				throw new NoStockException(skuId);
			}
			for (Long wareId : wareIds) {
				//成功就返回1，否则就是0
				Long count = wareSkuDao.lockSkuStock(skuId,wareId,hasStock.getNum());
				if (count == 1){
					skuStocked = true;
					//TODO 告诉MQ库存锁定成功
					WareOrderTaskDetailEntity entity = new WareOrderTaskDetailEntity(null,skuId,null,hasStock.getNum(),taskEntity.getId(),wareId,null);
					orderTaskDetailService.save(entity);
					StockLockedTo lockedTo = new StockLockedTo();
					lockedTo.setId(taskEntity.getId());
					StockDetailTo stockDetailTo = new StockDetailTo();
					BeanUtils.copyProperties(entity,stockDetailTo);
					//只发id不行，防止回滚以后找不到数据
					lockedTo.setStockDetailTo(stockDetailTo);
					// rabbitTemplate
					rabbitTemplate.convertAndSend("stock-event-exchange","stock.locked",lockedTo);
					break;
				}else {
					//当前仓库锁库存失败，重试下一个
				}
			}
			if (skuStocked == false){
				//当前商品所有仓库都没有锁住
				throw  new NoStockException(skuId);
			}
		}


		//全部商品项锁定库存成功
    	return true;
	}

	@Override
	public void unlockStock(StockLockedTo to) {
			Long id = to.getId();    //库存工作单的id
			StockDetailTo detail = to.getStockDetailTo();
			Long detailId = detail.getId();
			/**
			 * 解锁
			 * 1、查询数据库关于这个订单的锁定库存信息
			 * 	有：证明库存锁定成功了
			 * 		解锁：订单情况。
			 * 			1、没有这个订单。必须解锁
			 * 			2、有这个订单，不是解锁库存。
			 * 					订单状态：
			 * 						已取消：解锁库存。
			 * 						没取消：不能解锁；
			 * 	没有：库存锁定失败了，库存回滚了，这种情况无需解锁
			 */
			WareOrderTaskDetailEntity byId = orderTaskDetailService.getById(detailId);
			if (byId != null) {
				//解锁
				Long id1 = to.getId();
				WareOrderTaskEntity taskEntity = orderTaskService.getById(id1);
				String orderSn = taskEntity.getOrderSn();//根据订单号查询订单的状态
				R r = orderFeignService.getOrderStatus(orderSn);
				if (r.getCode() == 0) {
					//订单数据返回成功
					OrderVo data = r.getData(new TypeReference<OrderVo>() {
					});
					if (data == null || data.getStatus() == 4) {
						//订单不存在
						//订单已经被取消了，才能解锁库存
						//detailId
						if (byId.getLockStatus() == 1){
							//当前库存工作单详情，状态1为已锁定但是未解锁才可以解锁
							unLockStock(detail.getSkuId(), detail.getWareId(), detail.getSkuNum(), detailId);
						}
					}
				} else {
					//消息拒绝以后重新放到队列里面，让别人继续消费解锁
					throw new RuntimeException("远程调用失败");
				}
			} else {
				//无需解锁
				// channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
			}

	}


	//防止订单订单服务卡顿，导致订单状态消息一直改不了，库存消息优先到期，查订单状态还是新建状态
	//导致卡顿的订单，永远不能解锁库存
	@Override
	public void unlockStock(OrderTo orderTo) {
		String orderSn = orderTo.getOrderSn();
		//查一下最新库存的状态，防止重复解锁库存
		WareOrderTaskEntity task = orderTaskService.getOrderTaskByOrderSn(orderSn);
		Long id = task.getId();
		//按照工作单找到所有 没有解锁的库存，进行解锁
		List<WareOrderTaskDetailEntity> list = orderTaskDetailService.list(
				new QueryWrapper<WareOrderTaskDetailEntity>()
						.eq("task_id", id)
						.eq("lock_status", 1));
		for (WareOrderTaskDetailEntity entity : list) {
			// Long skuId, Long wareId, Integer skuNum, Long detailId
			unLockStock(entity.getSkuId(),entity.getWareId(),entity.getSkuNum(),entity.getId());
		}
	}


	@Data
	class SkuWareHasStock{
    	private Long skuId;
    	private Integer num;
    	private List<Long> wareId;
	}

}